home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / MA3.1.1 & CW4.5 / Modifications / *OR* replace these files / UMenuMgr.cp < prev    next >
Encoding:
Text File  |  1994-09-17  |  60.9 KB  |  1,993 lines  |  [TEXT/MPS ]

  1. /*
  2. *    This file has been changed from the original MacApp 3.1.1
  3. *    to support the metrowerks CodeWarrior compilers C/C++ 1.1.1.
  4. *    These changes are known *not* to work with earlier versions
  5. *    of CodeWarrior.  Every attempt though has been made to to keep 
  6. *    this file compatible with other development environments.
  7. *
  8. *    Mark Anderson
  9. *    metrowerks
  10. *    9/16/94
  11. *
  12. */
  13.  
  14. //----------------------------------------------------------------------------------------
  15. // UMenuMgr.cp 
  16. // Copyright © 1984-1994 by Apple Computer Inc. All rights reserved.
  17. //----------------------------------------------------------------------------------------
  18.  
  19.  
  20. //----------------------------------------------------------------------------------------
  21. // Theory of Operation
  22. //
  23. // This unit provides two features: It implements a command numbering system that is
  24. // independent of menu/ item placement, and implements a framework for optimizing menu
  25. // setups. The command numbering system works by assigning commands a unique command
  26. // number, and providing a mechanism for mapping command numbers to menu/ item pairs. A
  27. // set of routines are provide to manipulate commands via their command number rather
  28. // than their menu and item numbers.
  29. //
  30. // Each command can be assigned an integer command number from 1 to 32767. To associate a
  31. // command number with a menu item, menu resources are defined with the 'CMNU' resource
  32. // type--not the 'MENU' type. The 'CMNU' type is just like the 'MENU' type, with an
  33. // additional command number field for each menu item. This unit converts the 'CMNU'
  34. // resource into a 'MENU' dynamically at run time.
  35. //
  36. // The items of some menus cannot be determined until run-time. The font menu is an
  37. // example. In such cases, no command number is assigned by you. Instead, the command
  38. // number is equal to -(256 * menu + item). The procedure CommandToMenuItem converts a
  39. // command number to a menu id and item number by the following method:
  40. //
  41. // - If the command number is positive, the command table is searched for the number. If
  42. // it is found, CommandToMenuItem returns the corre- sponding menu id and item
  43. // number. Otherwise the menu and item are zero.
  44. //
  45. // - If the command number is negative, the menu number is the upper eight bits, and the
  46. // item number the lower eight bits, of the absolute value of the command number. (This
  47. // implies that menu id's must be <= 127 and item numbers must be <= 255.) The function
  48. // CommandFromMenuItem converts menu/ items to command numbers by the following method:
  49. //
  50. // - If the item number is positive, the command table is search for the given menu/ item
  51. // pair.  If found, the corresponding command number is returned. If not found, the number
  52. // returned is equal to
  53. //  -(256 * menu + item).
  54. //  - If the item number is negative, the number returned is equal to
  55. //  -item number.
  56. //
  57. // Note that CommandToMenuItem and CommandFromMenuItem work regardless of whether the
  58. // command is actually installed in the menu bar. MacApp takes advantage of this feature
  59. // by having a set of generic "buzz" commands, whose primary use is to set the name of the
  60. // Undo command (e.g. 'Undo Drawing').
  61. //
  62. // The second feature of this unit is to optimize menu setups (changing the appearance of
  63. // menus and items). Normally, each call to CheckItem, SetItemStyle and SetCommandIcon in
  64. // turn calls CalcMenuSize because the width or height of the menu may have changed. If
  65. // menu setups are done all at one time, then CalcMenuSize can be deferred until the end
  66. // of the setup process. The procedure PerformMenuSetup implements this mechanism. It relies
  67. // on the fact that menu setups are done all at once, and that you will call
  68. // SetCommandName, SetItemStyle and SetCommandIcon instead of SetItem, SetItemStyle and
  69. // SetCommandIcon. It works only for menus whose id is from 1 to mLastMenu. Menus with IDs
  70. // greater than mLastMenu are not affected by this scheme.
  71. //
  72. // PerformMenuSetup accepts one parameter, a procedure which actually implements the menu
  73. // appearance changes. SetupMenus performs the following steps:
  74. //
  75. // - Before calling your menu setup procedure, StartupMenuSetup is called. It disables all
  76. // menus and items, remembers the current menu proc and enabled flags of each menu, and
  77. // sets the MenuProc of each menu to gHNullMenuProc, thereby disabling CalcMenuSize.
  78. //
  79. // - Your procedure is called.It in turn calls SetCommandName, SetCmdStyle, SetCommandIcon,
  80. // Enable, EnableCheck, or a Toolbox routine (provided it isn't SetItem, SetItemStyle or
  81. // SetCommandIcon).
  82. //
  83. // - Menus with at least one enabled item are enabled, CalcMenuSize is called for those
  84. // menus that need it, each menu's menuproc is restored, and DrawMenuBar is called if the
  85. // enabled state of any menu changed.
  86. //----------------------------------------------------------------------------------------
  87.  
  88. #ifndef __UMENUMGR__
  89. #include <UMenuMgr.h>
  90. #endif
  91.  
  92. #ifndef __STDIO__
  93. #include <stdio.h>
  94. #endif
  95.  
  96. #ifndef __GEOMETRY__
  97. #include <Geometry.h>
  98. #endif
  99.  
  100. #ifndef __MEMORY__
  101. #include <Memory.h>
  102. #endif
  103.  
  104. #ifndef __UOBJECT__
  105. #include <UObject.h>
  106. #endif
  107.  
  108. #ifndef __UFAILURE__
  109. #include <UFailure.h>
  110. #endif
  111.  
  112. #ifndef __ULIST__
  113. #include <UList.h>
  114. #endif
  115.  
  116. #ifndef __UPATCH__
  117. #include <UPatch.h>
  118. #endif
  119.  
  120. #ifndef __UMEMORY__
  121. #include <UMemory.h>
  122. #endif
  123.  
  124. #ifndef __TEXTEDIT__
  125. #include <TextEdit.h>
  126. #endif
  127.  
  128. #ifndef __OSUTILS__
  129. #include <OSUtils.h>
  130. #endif
  131.  
  132. #ifndef __UMACAPPUTILITIES__
  133. #include <UMacAppUtilities.h>
  134. #endif
  135.  
  136. #ifndef __UMACAPPGLOBALS__
  137. #include <UMacAppGlobals.h>
  138. #endif
  139.  
  140. #ifndef __TRAPS__
  141. #include <Traps.h>
  142. #endif
  143.  
  144. #ifndef __TOOLUTILS__
  145. #include <ToolUtils.h>
  146. #endif
  147.  
  148. #ifndef __RESOURCES__
  149. #include <Resources.h>
  150. #endif
  151.  
  152. #ifndef __UITERATOR__
  153. #include <UIterator.h>
  154. #endif
  155.  
  156. #ifndef __UAPPLICATION__
  157. #include <UApplication.h>
  158. #endif
  159.  
  160. #ifndef __BALLOONS__
  161. #include <Balloons.h>
  162. #endif
  163.  
  164. #ifndef __LOWMEM__
  165. #include <LowMem.h>
  166. #endif
  167.  
  168. //----------------------------------------------------------------------------------------
  169. const Boolean kHierarchical = true;
  170. const Boolean kNotHierarchical = !kHierarchical;
  171.  
  172. const Boolean kDoHierarchical = true;
  173. const Boolean kDontDoHierarchical = !kDoHierarchical;
  174.  
  175. typedef struct MenuCmdRecord
  176. {
  177.     CommandNumber theCmdNumber;
  178.     ResNumber theMenuNumber;
  179.     short theItemNumber;
  180. }    *MenuCmdRecordPtr, ** MenuCmdRecordHandle;
  181.  
  182. //----------------------------------------------------------------------------------------
  183. // TCmdTable:
  184. //----------------------------------------------------------------------------------------
  185.  
  186. DeclareClassDesc(TCmdTable);
  187.  
  188. class TCmdTable : public TSortedDynamicArray
  189. {
  190.     DeclareClass(TCmdTable);
  191.     
  192. public:
  193.     void ICmdTable();
  194.     virtual CompareResult CompareElements(void* Element1,
  195.                                           void* Element2);    // override 
  196.         
  197.     virtual void CommandToMenuItem(CommandNumber theCommand,
  198.                                    MenuID& menu,
  199.                                    short& item);
  200.     virtual CommandNumber CommandFromMenuItem(short menu, short item);
  201.     // Given a menuID,item # return the appropriate command number. 
  202.     // If there is no such command number, return -BOR(((menu) << 8), item). 
  203.     // If the item number is <0 then assume that it is a negative command number.
  204.  
  205.     void AddToTable(CommandNumber commandNumber,
  206.                     MenuID menuNumber,
  207.                     short itemNumber);
  208.     
  209.     void AddNewCmdToTableAndUpdateTable(CommandNumber commandNumber,
  210.                                           MenuID menuNumber,
  211.                                            short itemNumber);
  212.         // This adds a menu item/command number after the menus have already been 
  213.         // set up, and updates all the tables
  214.     
  215.     void DeleteCmdAndUpdateTable(CommandNumber theMenuItemCommandNumber);
  216.         // This deletes a menu item/command number after the menus have already
  217.         // been set up, and updates all the tables
  218. };
  219.  
  220.  
  221. //----------------------------------------------------------------------------------------
  222. // TMenuTable:
  223. //----------------------------------------------------------------------------------------
  224.  
  225. DeclareClassDesc(TMenuTable);
  226.  
  227. class TMenuTable : public TSortedHandleList
  228. {
  229.     DeclareClass(TMenuTable);
  230.     
  231. public:
  232.     void IMenuTable();
  233.     MenuHandle GetMenu(MenuID menuID);
  234.     virtual CompareResult Compare(Handle item1, Handle item2);    // override 
  235. };
  236.  
  237.  
  238. typedef struct MenuIDRecord
  239. {
  240.     ResNumber        fMenuResID;
  241.     MenuID            fMenuID;
  242. }    *MenuIDRecordPtr, **MenuIDRecordHandle;
  243.  
  244.  
  245. //----------------------------------------------------------------------------------------
  246. // TMenuIDList:
  247. //----------------------------------------------------------------------------------------
  248.  
  249. DeclareClassDesc(TMenuIDList);
  250.  
  251. class TMenuIDList: public TSortedDynamicArray
  252. {
  253.     DeclareClass(TMenuIDList);
  254.     
  255. public:
  256.     void IMenuIDList();
  257.     virtual CompareResult CompareElements(void* Element1, void* Element2);    // override 
  258.         
  259.     MenuID MenuIDFromResID(ResNumber menuResID);
  260.  
  261.     void AddToTable(ResNumber menuResID, MenuID menuID);
  262. };
  263.  
  264.  
  265. Handle pHNullMenuProc = NULL;                // Handle to NULL menu proc 
  266.  
  267. TCmdTable* gCmdTable = NULL;                // command numbers and their associated menu
  268.                                             // and item numbers
  269.                                                         
  270. TMenuTable* gMenuTable = NULL;                // list of menus created/managed by MacApp 
  271.  
  272. TMenuIDList* gMenuIDList;                    // list of menu IDs sorted by resource ID
  273.  
  274. pascal void NullMenuProc(short message,
  275.                          MenuHandle aMenuHandle,
  276.                          CRect& menuRect,
  277.                          CPoint hitPt,
  278.                          short& whichItem);
  279.  
  280. //----------------------------------------------------------------------------------------
  281.  
  282. static Boolean gMenusAreInvalid = true;
  283.     // Used by InvalidateMenus to track whether menus need to be setup.
  284.  
  285. static Boolean gMenuBarIsInvalid = true;
  286.     // Used by InvalidateMenuBar, if the InvalMenuBar trap is not implemented, to track
  287.     // whether the menubar is invalid and will need redrawing.
  288.  
  289. TMenuBarManager* gMenuBarManager = NULL;
  290.  
  291. #if qDebug
  292. Boolean gTraceSetupMenus = false;
  293. #endif
  294.  
  295.  
  296. //========================================================================================
  297. // struct CGetMenuID
  298. //========================================================================================
  299.  
  300. struct CGetMenuID
  301. {
  302. public:
  303.     // Fields
  304.     ResNumber&        menuResID;
  305.     TMenuIDList*    theMenuIDList;
  306.  
  307.     // Constructor
  308.     CGetMenuID(ResNumber& aMenuResID, TMenuIDList* aMenuIDList) :
  309.         menuResID(aMenuResID),
  310.         theMenuIDList(aMenuIDList)
  311.     {
  312.     }
  313. };
  314.  
  315.  
  316. //----------------------------------------------------------------------------------------
  317. // TestMenuResIDs: 
  318. //----------------------------------------------------------------------------------------
  319. #pragma segment MAMenuRes
  320.  
  321. CompareResult TestMenuResIDs(ArrayIndex anItem, void* staticLink)
  322. {
  323.     CGetMenuID* testInfo = (CGetMenuID*)staticLink;
  324.     ResNumber theMenuResIDitem;
  325.  
  326.     theMenuResIDitem = ((MenuIDRecordPtr)testInfo->theMenuIDList->ComputeAddress(anItem))->fMenuResID;
  327.  
  328.     if (theMenuResIDitem > testInfo->menuResID)
  329.         return kItemGreaterThanCriteria;
  330.     else if (theMenuResIDitem < testInfo->menuResID)
  331.         return kItemLessThanCriteria;
  332.     else
  333.         return kItemEqualCriteria;
  334. } // TestMenuResIDs 
  335.  
  336.  
  337. //========================================================================================
  338. // CLASS TMenuIDList
  339. //========================================================================================
  340. #undef Inherited
  341. #define Inherited TSortedDynamicArray
  342.  
  343. #pragma segment MAInit
  344. DefineClass(TMenuIDList, Inherited);
  345.  
  346. //----------------------------------------------------------------------------------------
  347. // TMenuIDList::IMenuIDList: 
  348. //----------------------------------------------------------------------------------------
  349. #pragma segment MAInit
  350.  
  351. void TMenuIDList::IMenuIDList()
  352.  
  353. {
  354.     this->ISortedDynamicArray(0, sizeof(MenuIDRecord));
  355. } // TMenuIDList::IMenuIDList 
  356.  
  357. //----------------------------------------------------------------------------------------
  358. // TMenuIDList::CompareElements: 
  359. //----------------------------------------------------------------------------------------
  360. #pragma segment MAMenuRes
  361.  
  362. CompareResult TMenuIDList::CompareElements(void* Element1, void* Element2)    // override 
  363.  
  364. {
  365.     ResNumber theResNumber1 = ((MenuIDRecordPtr)Element1)->fMenuResID;
  366.     ResNumber theResNumber2 = ((MenuIDRecordPtr)Element2)->fMenuResID;
  367.  
  368.     if (theResNumber1 > theResNumber2)
  369.         return kItem1GreaterThanItem2;
  370.     else if (theResNumber1 < theResNumber2)
  371.         return kItem1LessThanItem2;
  372.     else
  373.         return kItem1EqualItem2;
  374. } // TMenuIDList::CompareElements 
  375.  
  376. //----------------------------------------------------------------------------------------
  377. // TMenuIDList::AddToTable: 
  378. //----------------------------------------------------------------------------------------
  379. #pragma segment MAMenuRes
  380.  
  381. void TMenuIDList::AddToTable(ResNumber menuResID, MenuID menuID)
  382. {
  383.     MenuIDRecord arec;
  384.  
  385.     arec.fMenuResID = menuResID;
  386.     arec.fMenuID = menuID;
  387.  
  388.     this->InsertElementInOrder((Ptr) & arec);
  389. } // TMenuIDList::AddToTable 
  390.  
  391. //----------------------------------------------------------------------------------------
  392. // TMenuIDList::MenuIDFromResID: 
  393. //----------------------------------------------------------------------------------------
  394. #pragma segment MAMenuRes
  395.  
  396. MenuID TMenuIDList::MenuIDFromResID(ResNumber menuResID)
  397.  
  398. {
  399.     ArrayIndex index;
  400.     CGetMenuID aCGetMenuID(menuResID,this);
  401.  
  402.     if (this->DoSearchElement(&TestMenuResIDs, &aCGetMenuID, index))
  403.     {
  404.         MenuIDRecordPtr aMenuIDListPtr = (MenuIDRecordPtr)ComputeAddress(index);
  405.         return aMenuIDListPtr->fMenuID;
  406.     }
  407.  
  408.     return 0;
  409. } // TMenuIDList::MenuIDFromResID 
  410.  
  411.  
  412. //========================================================================================
  413. // CLASS TCmdTable
  414. //========================================================================================
  415. #undef Inherited
  416. #define Inherited TSortedDynamicArray
  417.  
  418. #pragma segment MAInit
  419. DefineClass(TCmdTable, Inherited);
  420.  
  421. //----------------------------------------------------------------------------------------
  422. // TCmdTable::ICmdTable: 
  423. //----------------------------------------------------------------------------------------
  424. #pragma segment MAInit
  425.  
  426. void TCmdTable::ICmdTable()
  427.  
  428. {
  429.     this->ISortedDynamicArray(0, sizeof(MenuCmdRecord));
  430. } // TCmdTable::ICmdTable 
  431.  
  432. //----------------------------------------------------------------------------------------
  433. // TCmdTable::CompareElements: 
  434. //----------------------------------------------------------------------------------------
  435. #pragma segment MAMenuRes
  436.  
  437. CompareResult TCmdTable::CompareElements(void* Element1, void* Element2)    // override 
  438.  
  439. {
  440.     CommandNumber theCommanditem1 = ((MenuCmdRecordPtr)Element1)->theCmdNumber;
  441.     CommandNumber theCommanditem2 = ((MenuCmdRecordPtr)Element2)->theCmdNumber;
  442.  
  443.     if (theCommanditem1 > theCommanditem2)
  444.         return kItem1GreaterThanItem2;
  445.     else if (theCommanditem1 < theCommanditem2)
  446.         return kItem1LessThanItem2;
  447.     else
  448.         return kItem1EqualItem2;
  449. } // TCmdTable::CompareElements 
  450.  
  451. //--------------------------------------------------------------------------------------------------
  452.  
  453. class CCmdToMenuItem
  454. {
  455. public:
  456.     CommandNumber& theCommand;
  457.     TCmdTable* theCmdTable;
  458.     
  459.     CCmdToMenuItem(CommandNumber& aCommand,
  460.                    TCmdTable* aCmdTable) :
  461.         theCommand(aCommand),
  462.         theCmdTable(aCmdTable)
  463.     {
  464.     }
  465. };
  466.  
  467. #pragma segment MAMenuRes
  468. CompareResult CmdToMenuItem_TestItem(ArrayIndex anItem, void* staticLink)
  469. {
  470.     CCmdToMenuItem* testInfo = (CCmdToMenuItem*)staticLink;
  471.     CommandNumber theCommanditem;
  472.  
  473.     theCommanditem = ((MenuCmdRecordPtr)testInfo->theCmdTable->ComputeAddress(anItem))->theCmdNumber;
  474.  
  475.     if (theCommanditem > testInfo->theCommand)
  476.         return kItemGreaterThanCriteria;
  477.     else if (theCommanditem < testInfo->theCommand)
  478.         return kItemLessThanCriteria;
  479.     else
  480.         return kItemEqualCriteria;
  481. }
  482.  
  483. //----------------------------------------------------------------------------------------
  484. // TCmdTable::CommandToMenuItem: 
  485. //----------------------------------------------------------------------------------------
  486. #pragma segment MAMenuRes
  487.  
  488. void TCmdTable::CommandToMenuItem(CommandNumber theCommand,
  489.                                   MenuID& menu,
  490.                                   short& item)
  491. {
  492.     ArrayIndex                index = 0;
  493.     MenuCmdRecordPtr        aMenuCmdRecordPtr;
  494.     CCmdToMenuItem            aCCmdToMenuItem(theCommand, this);
  495.     
  496.     if (theCommand < 0) /* negative commands are mapped not table based */
  497.     {
  498.         menu = (short)((-theCommand) >> 8);
  499.         item = (short)((-theCommand) & 255);
  500.     }
  501.     else
  502.     {
  503.         if (this->DoSearchElement(&CmdToMenuItem_TestItem, &aCCmdToMenuItem, index))
  504.         {
  505.             do
  506.             {
  507.                 index--;
  508.                 if (index == 0)
  509.                     break;
  510.                 aMenuCmdRecordPtr = (MenuCmdRecordPtr)ComputeAddress(index);
  511.             }
  512.             while (aMenuCmdRecordPtr->theCmdNumber == theCommand);
  513.             
  514.             ++index;
  515.             
  516.             do
  517.             {
  518.                 aMenuCmdRecordPtr = (MenuCmdRecordPtr)ComputeAddress(index);
  519.                 if (aMenuCmdRecordPtr->theCmdNumber == theCommand)
  520.                 {
  521.                     menu = aMenuCmdRecordPtr->theMenuNumber;
  522.                     item = aMenuCmdRecordPtr->theItemNumber;
  523.                     if (::GetMenuHandle(menu) != NULL)
  524.                         break;
  525.                 }
  526.                 ++index;
  527.             }
  528.             while (aMenuCmdRecordPtr->theCmdNumber == theCommand);
  529.         }
  530.         else// not found
  531.         {
  532.             menu = 0;
  533.             item = 0;
  534.         }
  535.     }    // else
  536. } // TCmdTable::CommandToMenuItem
  537.  
  538. //----------------------------------------------------------------------------------------
  539. // TCmdTable::CommandFromMenuItem: 
  540. //----------------------------------------------------------------------------------------
  541. #pragma segment MAMenuRes
  542.  
  543. CommandNumber TCmdTable::CommandFromMenuItem(short menu, short item)
  544.                                             
  545. // Given a menuID/item # return the appropriate command number. if there
  546. // is no such command number, return -BOR(((menu) << 8), item).  If the
  547. // item number is <0 then assume that it is a negative command number.
  548.  
  549. {
  550.     if (item < 0)
  551.         return -item;
  552.     else
  553.     {
  554.         if (item > 0)
  555.         {
  556.             // Search the table linearly. 
  557.             for (ArrayIndex i = 1; i <= this->GetSize(); ++i)
  558.             {
  559.                 MenuCmdRecordPtr aMenuCmdRecordPtr = (MenuCmdRecordPtr)this->ComputeAddress(i);
  560.                 if ((menu == aMenuCmdRecordPtr->theMenuNumber) && (item == aMenuCmdRecordPtr->theItemNumber))
  561.                 {
  562.                     return aMenuCmdRecordPtr->theCmdNumber;
  563.                 }
  564.             }
  565.         }
  566.  
  567. #if qDebugMsg
  568.         if ((menu > 127) || (item > 255))
  569.         {
  570.             fprintf(stderr, "menu : %1d , item : %1d \n", menu, item);
  571.             fprintf(stderr, "Menu/item number is too big for a negative command number!\n");
  572.             ProgramBreak("Try using a negative item number instead.");
  573.         }
  574. #endif
  575.  
  576.         return -((menu << 8) | item);
  577.     }
  578. } // TCmdTable::CommandFromMenuItem 
  579.  
  580. //----------------------------------------------------------------------------------------
  581. // TCmdTable::AddToTable: 
  582. //----------------------------------------------------------------------------------------
  583. #pragma segment MAInit
  584.  
  585. void TCmdTable::AddToTable(CommandNumber commandNumber,
  586.                            MenuID menuNumber,
  587.                            short itemNumber)
  588. {
  589.     MenuCmdRecord arec;
  590.  
  591.     if (commandNumber > 0)                            // Negative numbers are mapped not tabled 
  592.     {
  593.         arec.theCmdNumber = commandNumber;
  594.         arec.theMenuNumber = menuNumber;
  595.         arec.theItemNumber = itemNumber;
  596.  
  597.         this->InsertElementInOrder((Ptr) & arec);
  598.     }
  599. } // TCmdTable::AddToTable 
  600.  
  601.  
  602. //----------------------------------------------------------------------------------------
  603. // TCmdTable::AddNewCmdToTableAndUpdateTable:
  604. //----------------------------------------------------------------------------------------
  605. #pragma segment MAMenuRes
  606.  
  607. void TCmdTable::AddNewCmdToTableAndUpdateTable(CommandNumber commandNumber,
  608.                                                  MenuID menuNumber,
  609.                                                   short itemNumber)
  610. {
  611.     MenuCmdRecord     arec;
  612.  
  613.     for (ArrayIndex i = 1; i <= this->GetSize(); i++)
  614.     {
  615.         this->GetElementsAt(i, &arec, 1);
  616.         
  617.         if ((arec.theMenuNumber == menuNumber) && (arec.theItemNumber >= itemNumber))
  618.         {
  619.             // If we have found an item in the same menu as we are adding to and it is
  620.             // the same index or greater then bump its itemNumber
  621.             arec.theItemNumber++;
  622.             
  623.             // Write it back out
  624.             this->ReplaceElementsAt(i, &arec, 1);
  625.         }
  626.     }
  627.     
  628.     // Insert the new menu item
  629.     arec.theCmdNumber = commandNumber;
  630.     arec.theMenuNumber = menuNumber;
  631.     arec.theItemNumber = itemNumber;
  632.  
  633.     this->InsertElementInOrder((Ptr) &arec);
  634. } // TCmdTable::AddNewCmdToTableAndUpdateTable 
  635.  
  636. //----------------------------------------------------------------------------------------
  637. // TCmdTable::DeleteCmdAndUpdateTable:
  638. //----------------------------------------------------------------------------------------
  639. #pragma segment MAMenuRes
  640.  
  641. void TCmdTable::DeleteCmdAndUpdateTable(CommandNumber theMenuItemCommandNumber)
  642. {
  643.     MenuCmdRecord     arec;
  644.     short            menuNumber;
  645.     short            itemNumber;
  646.     
  647.     this->CommandToMenuItem(theMenuItemCommandNumber, menuNumber, itemNumber);
  648.  
  649.     for (ArrayIndex i = 1; i <= this->GetSize(); i++)
  650.     {
  651.         this->GetElementsAt(i, &arec, 1);
  652.         
  653.         if ((arec.theMenuNumber == menuNumber) && (arec.theItemNumber > itemNumber))
  654.         {
  655.             // If we have found an item in the same menu as we are deleting from and its
  656.             // index is greater then decrement its itemNumber
  657.             arec.theItemNumber--;
  658.             
  659.             // Write it back out
  660.             this->ReplaceElementsAt(i, &arec, 1);
  661.         }
  662.         else if ((arec.theMenuNumber == menuNumber) && (arec.theItemNumber == itemNumber))
  663.         {
  664.             // Delete the element
  665.             this->DeleteElementsAt(i, 1);
  666.         }
  667.     }
  668. } // TCmdTable::DeleteCmdAndUpdateTable 
  669.  
  670. //----------------------------------------------------------------------------------------
  671. // TestForMenuID: 
  672. //----------------------------------------------------------------------------------------
  673. #pragma segment MAMenuRes
  674. CompareResult TestForMenuID(Handle anItem, void* staticLink)
  675. {
  676.     MenuID* menuID = (MenuID*)staticLink;
  677.     
  678.     short menuIDitem = (*((MenuHandle)anItem))->menuID;
  679.  
  680.     if (menuIDitem > *menuID)
  681.         return kItemGreaterThanCriteria;
  682.     else if (menuIDitem < *menuID)
  683.         return kItemLessThanCriteria;
  684.     else
  685.         return kItemEqualCriteria;
  686. } // TestForMenuID 
  687.  
  688.  
  689. //========================================================================================
  690. // CLASS TMenuTable
  691. //========================================================================================
  692. #undef Inherited
  693. #define Inherited TSortedHandleList
  694.  
  695. #pragma segment MAInit
  696. DefineClass(TMenuTable, Inherited);
  697.  
  698. //----------------------------------------------------------------------------------------
  699. // TMenuTable::IMenuTable: 
  700. //----------------------------------------------------------------------------------------
  701. #pragma segment MAInit
  702.  
  703. void TMenuTable::IMenuTable()
  704.  
  705. {
  706.     this->ISortedHandleList();
  707. } // TMenuTable::IMenuTable 
  708.  
  709. //----------------------------------------------------------------------------------------
  710. // TMenuTable::GetMenu: 
  711. //----------------------------------------------------------------------------------------
  712. #pragma segment MAMenuRes
  713.  
  714. MenuHandle TMenuTable::GetMenu(MenuID menuID)
  715.  
  716. {
  717.     ArrayIndex index;
  718.  
  719.     return ((MenuHandle)this->DoSearch(&TestForMenuID, &menuID, index));    // discard index 
  720. } // TMenuTable::GetMenu 
  721.  
  722. //----------------------------------------------------------------------------------------
  723. // TMenuTable::Compare: 
  724. //----------------------------------------------------------------------------------------
  725. #pragma segment MAMenuRes
  726.  
  727. CompareResult TMenuTable::Compare(Handle item1, Handle item2)    // override 
  728.  
  729. {
  730.     MenuID menuID1 = (*((MenuHandle)item1))->menuID;
  731.     MenuID menuID2 = (*((MenuHandle)item2))->menuID;
  732.  
  733.     if (menuID1 > menuID2)
  734.         return kItem1GreaterThanItem2;
  735.     else if (menuID1 < menuID2)
  736.         return kItem1LessThanItem2;
  737.     else
  738.         return kItem1EqualItem2;
  739. } // TMenuTable::Compare 
  740.  
  741.  
  742. //========================================================================================
  743. // GLOBAL Procedures
  744. //========================================================================================
  745. #undef Inherited
  746.  
  747. #if qDebugMsg
  748.  
  749. //----------------------------------------------------------------------------------------
  750. // TraceMenuName: 
  751. //----------------------------------------------------------------------------------------
  752. #pragma segment MADebug
  753.  
  754. char TraceMenuName(CommandNumber aCommand)
  755. // For debugging purposes only--used to dump the name and number of a command 
  756.  
  757. {
  758.     CStr255 cmdName;
  759.  
  760.     CommandToName(aCommand, cmdName);
  761.     fprintf(stderr, " %1d [%s],", aCommand, (char *) cmdName);
  762.     return ' ';
  763. } // TraceMenuName 
  764.  
  765. #endif
  766.  
  767. //----------------------------------------------------------------------------------------
  768. // InvalidateMenus: 
  769. //----------------------------------------------------------------------------------------
  770. #pragma segment MAMenuRes
  771.  
  772. void InvalidateMenus()
  773. {
  774.     gMenusAreInvalid = true;
  775. } // InvalidateMenus 
  776.  
  777. //----------------------------------------------------------------------------------------
  778. #pragma segment MAMenuRes
  779.  
  780. struct MenuBarRecord
  781. {
  782.     ResNumber nMenus;
  783.     ResNumber menuResID[1000];
  784. };
  785.  
  786. //----------------------------------------------------------------------------------------
  787. // AddMenuBar: 
  788. //----------------------------------------------------------------------------------------
  789. typedef MenuBarRecord* MenuBarPtr, ** MenuBarHandle;
  790.  
  791. void AddMenuBar(ResNumber itsID,
  792.                 Boolean isHierarchical)
  793.  
  794. {
  795.     short hier = 0;
  796.     MenuBarHandle hmbar;
  797.  
  798.     if (isHierarchical)
  799.         hier = -1;
  800.  
  801.     hmbar = (MenuBarHandle)GetResource('MBAR', itsID);
  802.     if (hmbar)
  803.     {
  804.         for (ResNumber i = 0; i < (*hmbar)->nMenus; ++i)
  805.         {
  806.             ResNumber menuResID = (*hmbar)->menuResID[i];
  807.             MenuID menuID = gMenuIDList->MenuIDFromResID(menuResID);
  808.             if (!::GetMenuHandle( menuID ))        // do nothing if it's already in menubar
  809.             {
  810.                 MenuHandle aMenu = MAGetMenu(menuResID);
  811.                 if (aMenu)
  812.                 {
  813.                     MAInsertMenu(aMenu, menuResID, hier);
  814.     
  815.                     // a visible menu needed insertion thus the menubar became invalid
  816.                     if (!isHierarchical)
  817.                         InvalidateMenuBar();
  818.                 }
  819.             }
  820.         }
  821.  
  822.         ReleaseResource((Handle)hmbar);
  823.         // hmbar = NULL;
  824.     }
  825. } // AddMenuBar 
  826.  
  827. //----------------------------------------------------------------------------------------
  828. // ValidateMenus: 
  829. //----------------------------------------------------------------------------------------
  830. #pragma segment MAMenuRes
  831.  
  832. void ValidateMenus()
  833.  
  834. {
  835.     gMenusAreInvalid = false;
  836. } // ValidateMenus 
  837.  
  838. //----------------------------------------------------------------------------------------
  839. // MenusHavePendingUpdate: 
  840. //----------------------------------------------------------------------------------------
  841. #pragma segment MAMenuRes
  842.  
  843. Boolean MenusHavePendingUpdate()
  844.  
  845. {
  846.     return gMenusAreInvalid;
  847. } // MenusHavePendingUpdate 
  848.  
  849. //----------------------------------------------------------------------------------------
  850. // InvalidateMenuBar: 
  851. //----------------------------------------------------------------------------------------
  852. #pragma segment MAMenuRes
  853.  
  854. void InvalidateMenuBar()
  855. {
  856.     InvalidateMenus();                            // if the menubar is invalidated then the
  857.                                                 // menu items must be also
  858.  
  859.     // On systems that have "InvalMenuBar" use that functionality. The system will redraw
  860.     // the menu bar at the next convenient time.
  861.     if (qNeedsSystem7 || TrapExists(_InvalMenuBar))
  862.         InvalMenuBar();
  863.     else
  864.         gMenuBarIsInvalid = true;
  865. } // InvalidateMenuBar 
  866.  
  867. //----------------------------------------------------------------------------------------
  868. // ValidateMenuBar: 
  869. //----------------------------------------------------------------------------------------
  870. #pragma segment MAMenuRes
  871.  
  872. static void ValidateMenuBar()
  873. {
  874.     gMenuBarIsInvalid = false;
  875. } // ValidateMenuBar 
  876.  
  877. //----------------------------------------------------------------------------------------
  878. // MenuBarHasPendingUpdate: 
  879. //----------------------------------------------------------------------------------------
  880. #pragma segment MAMenuRes
  881.  
  882. static Boolean MenuBarHasPendingUpdate()
  883.  
  884. {
  885.     return gMenuBarIsInvalid;
  886. } // MenuBarHasPendingUpdate 
  887.  
  888. //----------------------------------------------------------------------------------------
  889. // CommandEnabled: 
  890. //----------------------------------------------------------------------------------------
  891. #pragma segment MAMenuRes
  892.  
  893. Boolean CommandEnabled(CommandNumber command)
  894.  
  895. {
  896.     MenuID menuNo;
  897.     short itemNo;
  898.     MenuHandle theMenu;
  899.  
  900.     theMenu = CommandToComponents(command, menuNo, itemNo);
  901.  
  902.     if (theMenu)
  903.         if ((itemNo > 0) && (itemNo < 32))
  904.             return ((((*theMenu)->enableFlags >> itemNo) & 0x01) != 0);
  905.         else
  906.             return true;
  907.     else
  908.         return false;
  909. } // CommandEnabled 
  910.  
  911. //----------------------------------------------------------------------------------------
  912. // CommandFromMenuItem: 
  913. //----------------------------------------------------------------------------------------
  914. #pragma segment MAMenuRes
  915.  
  916. CommandNumber CommandFromMenuItem(short menu,
  917.                                  short item)
  918.  
  919. {
  920.     return gCmdTable->CommandFromMenuItem(menu, item);
  921. } // CommandFromMenuItem 
  922.  
  923. //----------------------------------------------------------------------------------------
  924. // CommandToMenuItem: 
  925. //----------------------------------------------------------------------------------------
  926. #pragma segment MAMenuRes
  927.  
  928. void CommandToMenuItem(CommandNumber aCommand,
  929.                        MenuID& menu,
  930.                        short& item)
  931.  
  932. {
  933.     gCmdTable->CommandToMenuItem(aCommand, menu, item);
  934. } // CommandToMenuItem 
  935.  
  936. //----------------------------------------------------------------------------------------
  937. // CommandToName: 
  938. //----------------------------------------------------------------------------------------
  939. #pragma segment MAMenuRes
  940.  
  941. void CommandToName(CommandNumber aCommand,
  942.                    CStr255& menuText)
  943.  
  944. {
  945.     short anItem;
  946.     ResNumber aMenu;
  947.  
  948.     menuText = "";
  949.  
  950.     MenuHandle mHandle = CommandToComponents(aCommand, aMenu, anItem);
  951.     if (mHandle)
  952.         GetMenuItemText(mHandle, anItem, menuText);
  953. } // CommandToName 
  954.  
  955. //----------------------------------------------------------------------------------------
  956. // CommandToComponents: 
  957. //----------------------------------------------------------------------------------------
  958. #pragma segment MAMenuRes
  959.  
  960. MenuHandle CommandToComponents(CommandNumber command,
  961.                                MenuID& menuNo,
  962.                                short& itemNo)
  963.  
  964. {
  965.     CommandToMenuItem(command, menuNo, itemNo);
  966.     if (menuNo)                                    // was found 
  967.         return MAGetMenuHandle(menuNo);
  968.     else
  969.         return NULL;
  970. } // CommandToComponents 
  971.  
  972. //----------------------------------------------------------------------------------------
  973. // Enable: 
  974. //----------------------------------------------------------------------------------------
  975. #pragma segment MAMenuRes
  976.  
  977. void Enable(CommandNumber aCommand,
  978.             Boolean canDo)
  979.  
  980. {
  981.     MenuID menu;
  982.     short item;
  983.  
  984. #if qDebugMsg
  985.     if (gTraceSetupMenus)
  986.         fprintf(stderr, "..... Enable(%c%s)\n", TraceMenuName(aCommand), (char *) gBoolString[canDo]);
  987. #endif
  988.  
  989.     MenuHandle aMenuHandle = CommandToComponents(aCommand, menu, item);
  990.     if (aMenuHandle)
  991.         if (canDo)
  992.             EnableItem(aMenuHandle, item);
  993.         else
  994.             DisableItem(aMenuHandle, item);
  995. } // Enable 
  996.  
  997. //----------------------------------------------------------------------------------------
  998. // EnableCheck: 
  999. //----------------------------------------------------------------------------------------
  1000. #pragma segment MAMenuRes
  1001.  
  1002. void EnableCheck(CommandNumber aCommand,
  1003.                  Boolean canDo,
  1004.                  Boolean checkIt)
  1005.  
  1006. {
  1007.     MenuID menu;
  1008.     short item;
  1009.     MenuHandle aMenuHandle;
  1010.  
  1011. #if qDebugMsg
  1012.     if (gTraceSetupMenus)
  1013.         fprintf(stderr, "..... EnableCheck(%c%s, %s)\n", 
  1014.                         TraceMenuName(aCommand),
  1015.                         (char *) gBoolString[canDo],
  1016.                         (char *) gBoolString[checkIt]);
  1017. #endif
  1018.  
  1019.     aMenuHandle = CommandToComponents(aCommand, menu, item);
  1020.     if (aMenuHandle)
  1021.     {
  1022.         if (canDo)
  1023.             EnableItem(aMenuHandle, item);
  1024.         else
  1025.             DisableItem(aMenuHandle, item);
  1026.         CheckItem(aMenuHandle, item, checkIt);
  1027.     }
  1028. } // EnableCheck 
  1029.  
  1030. //========================================================================================
  1031. // GLOBAL Procedures
  1032. //========================================================================================
  1033. #undef Inherited
  1034.  
  1035. //----------------------------------------------------------------------------------------
  1036. // GetResMenu: Allow us to get a menu when it's not available via ::GetMenuHandle.
  1037. //----------------------------------------------------------------------------------------
  1038. MenuHandle GetResMenu(ResNumber menuResID)
  1039. {
  1040.     MenuHandle theMenuHandle;
  1041.     FailInfo fi;
  1042.     
  1043.     short oldResFile = CurResFile();
  1044.     
  1045.     Try(fi)
  1046.     {
  1047.         UseResFile(gApplicationRefNum);
  1048.         theMenuHandle = (MenuHandle) GetResource('MENU', menuResID);
  1049.         fi.Success();
  1050.     }
  1051.     else
  1052.     {
  1053.         UseResFile(oldResFile);
  1054.         fi.ReSignal();
  1055.     }
  1056.     UseResFile(oldResFile);
  1057.  
  1058.     return theMenuHandle;
  1059. } // GetResMenu 
  1060.  
  1061. //----------------------------------------------------------------------------------------
  1062. // ConvertToMenu: 
  1063. //----------------------------------------------------------------------------------------
  1064. #pragma segment MAInit
  1065.  
  1066. MenuHandle ConvertToMenu(Handle CMNUHandle)
  1067. {
  1068.     MenuHandle theMenuHandle = NULL;
  1069.     Ptr theCMNUPtr;
  1070.     Ptr theMENUPtr;
  1071.     short i;
  1072.     MenuID menuNo;
  1073.     short itemNo;
  1074.     CommandNumber cmdNo;
  1075.     Ptr endPtr;
  1076.  
  1077.     theMenuHandle = (MenuHandle)NewPermHandle(GetHandleSize(CMNUHandle));
  1078.     LockHandleHigh(CMNUHandle);
  1079.     LockHandleHigh((Handle)theMenuHandle);
  1080.  
  1081.     theCMNUPtr = (Ptr)StripLong(*CMNUHandle);
  1082.     theMENUPtr = (Ptr)StripLong(*theMenuHandle);
  1083.     menuNo = *((IntegerPtr)theCMNUPtr);
  1084.  
  1085.     i = (*((CStr255 *)(theCMNUPtr + 14))).Length() + 15;
  1086.     BlockMove(theCMNUPtr, theMENUPtr, i);        // move menu header into MENU resource 
  1087.     theCMNUPtr = (Ptr)(theCMNUPtr + i);
  1088.     theMENUPtr = (Ptr)(theMENUPtr + i);
  1089.     itemNo = 0;
  1090.     endPtr = (Ptr)(theCMNUPtr + GetHandleSize(CMNUHandle));
  1091.     while ((theCMNUPtr < endPtr) && (((*((CStr255 *)theCMNUPtr)).Length()) != 0))
  1092.     {
  1093.         i = ((*((CStr255 *)theCMNUPtr)).Length()) + 5;
  1094.         BlockMove(theCMNUPtr, theMENUPtr, i);    // move menu item data sans command number 
  1095.         theCMNUPtr = (Ptr)(theCMNUPtr + i);
  1096.         theMENUPtr = (Ptr)(theMENUPtr + i);
  1097.         if ((((long)theCMNUPtr) & 0x00000001) == 1)// word align 
  1098.             theCMNUPtr = (Ptr)(theCMNUPtr + 1);
  1099.         cmdNo = *((CommandNumberPtr)theCMNUPtr);
  1100.         ++itemNo;
  1101.         theCMNUPtr = (Ptr) (theCMNUPtr + sizeof(CommandNumber));
  1102.  
  1103.         gCmdTable->AddToTable(cmdNo, menuNo, itemNo);
  1104.     }
  1105.     (*theMENUPtr) = 0;                            // termination mark 
  1106.     ++theMENUPtr;
  1107.     SetPermHandleSize((Handle)theMenuHandle, (Size)(theMENUPtr - StripLong((*theMenuHandle))));
  1108.  
  1109.     HUnlock(CMNUHandle);
  1110.     HUnlock((Handle)theMenuHandle);
  1111.     return theMenuHandle;
  1112. } // ConvertToMenu 
  1113.  
  1114. //----------------------------------------------------------------------------------------
  1115. // InitUMenuMgr: 
  1116. //----------------------------------------------------------------------------------------
  1117. #pragma segment MAInit
  1118.  
  1119. void InitUMenuMgr()
  1120. {
  1121.     short num;
  1122.     MenuHandle newMenu;
  1123.     Handle h;
  1124.     short i;
  1125.     ResNumber        menuResID;
  1126.     ResType            menuResourceType;
  1127.     Str255            menuResourceName;
  1128.  
  1129.     // Create the MenuResID -> MenuID translation table
  1130.     gMenuIDList = new TMenuIDList;
  1131.     gMenuIDList->IMenuIDList();
  1132.     
  1133.     // Create the command table 
  1134.     gCmdTable = new TCmdTable;
  1135.     gCmdTable->ICmdTable();
  1136.  
  1137.     // Create the menu table 
  1138.     gMenuTable = new TMenuTable;
  1139.     gMenuTable->IMenuTable();
  1140.  
  1141.     // initialize all CMNUs with positive id
  1142.     num = CountResources('CMNU');
  1143.     FailResError();
  1144.     for (i = 1; i <= num; ++i)
  1145.     {
  1146.         Handle aCMNUHandle = GetIndResource('CMNU', i);
  1147.         FailNILResource(aCMNUHandle);
  1148.         GetResInfo( aCMNUHandle, &menuResID, &menuResourceType, menuResourceName );
  1149.         short menuID = (* (MenuHandle) aCMNUHandle)->menuID;
  1150.         if (((* (MenuHandle) aCMNUHandle)->menuID) > 0)        // not in reserved range
  1151.         {
  1152.             // load the menudef and store it's reference in the menu 
  1153.             newMenu = ConvertToMenu(aCMNUHandle);
  1154.             h = GetResource('MDEF', *((short*)(&(*newMenu)->menuProc)) );
  1155.             (*newMenu)->menuProc = h;
  1156.  
  1157.             MAInsertInMenuTable(newMenu,menuResID);
  1158.         }
  1159.     }
  1160.  
  1161.     // initialize all MENUs with positive id
  1162.     num = CountResources('MENU');
  1163.     FailResError();
  1164.     for (i = 1; i <= num; ++i)
  1165.     {
  1166.         newMenu = (MenuHandle)GetIndResource('MENU', i);
  1167.         if (newMenu)
  1168.         {
  1169.             GetResInfo( (Handle)newMenu, &menuResID, &menuResourceType, menuResourceName );
  1170.  
  1171.             THz itsZone = HandleZone((Handle)newMenu);
  1172.             // not a System menu and not in reserved range
  1173.             if ((itsZone != SystemZone()) && ((*newMenu)->menuID) > 0)
  1174.             {
  1175.                 // load the menudef and store it's reference in the menu 
  1176.                 // h = GetResource('MDEF', (short)(((long)(*newMenu)->menuProc) >> sizeof(short)));
  1177.                 h = GetResource('MDEF', *((short*)(&(*newMenu)->menuProc)) );
  1178.                 (*newMenu)->menuProc = h;
  1179.         
  1180.                 MAInsertInMenuTable(newMenu,menuResID);
  1181.             }
  1182.         }
  1183.     }
  1184.  
  1185. #if !qPowerPC
  1186.     // Create the NULL menu proc 
  1187.     pHNullMenuProc = NewPermHandle(sizeof(JmpInstructionTemplate));
  1188.     PatchJmpInstruction(*pHNullMenuProc, (void*)StripLong(NullMenuProc));
  1189. #else
  1190.     // Create a MenuDefUPP for PowerPC builds…
  1191.     pHNullMenuProc = NewPermHandle(sizeof(RoutineDescriptor));
  1192.     RoutineDescriptor aMDEFUPP = BUILD_ROUTINE_DESCRIPTOR(uppMenuDefProcInfo, NullMenuProc);
  1193.     BlockMove(&aMDEFUPP, *pHNullMenuProc, sizeof(RoutineDescriptor));
  1194. #endif
  1195.  
  1196. #if qDebugMsg
  1197.     if (cUndo - cEditBase != kSysUndo)
  1198.         fprintf(stderr, "Invalid UNDO command number\n");
  1199.     if (cCut - cEditBase != kSysCut)
  1200.         fprintf(stderr, "Invalid CUT command number\n");
  1201.     if (cCopy - cEditBase != kSysCopy)
  1202.         fprintf(stderr, "Invalid COPY command number\n");
  1203.     if (cPaste - cEditBase != kSysPaste)
  1204.         fprintf(stderr, "Invalid PASTE command number\n");
  1205.     if (cClear - cEditBase != kSysClear)
  1206.         fprintf(stderr, "Invalid CLEAR command number\n");
  1207. #endif
  1208.  
  1209. } // InitUMenuMgr 
  1210.  
  1211. //----------------------------------------------------------------------------------------
  1212. // IsManagedMenu: 
  1213. //----------------------------------------------------------------------------------------
  1214. #pragma segment MAMenuRes
  1215.  
  1216. Boolean IsManagedMenu(MenuHandle theMenu)
  1217.  
  1218. {
  1219.     return gMenuTable->GetIdentityItemNo((Handle)theMenu) != kEmptyIndex;
  1220. } // IsManagedMenu 
  1221.  
  1222. //----------------------------------------------------------------------------------------
  1223. // MAGetMenuHandle: 
  1224. //----------------------------------------------------------------------------------------
  1225. #pragma segment MAMenuRes
  1226.  
  1227. MenuHandle MAGetMenuHandle(MenuID menuID)
  1228.  
  1229. {
  1230.     MenuHandle theMenu = ::GetMenuHandle(menuID);    // do this first ... the menu is likely to
  1231.                                                        // be in the menubar and more likely of
  1232.                                                     // success, hence, faster
  1233.  
  1234.     if (theMenu == NULL)                            // Try the menu list 
  1235.     {
  1236.         theMenu = gMenuTable->GetMenu(menuID);
  1237.     }
  1238.  
  1239.     return theMenu;
  1240. } // MAGetMenuHandle 
  1241.  
  1242. //----------------------------------------------------------------------------------------
  1243. // MAGetMenu: 
  1244. //----------------------------------------------------------------------------------------
  1245. #pragma segment MAMenuRes
  1246.  
  1247. MenuHandle MAGetMenu(ResNumber menuResID)
  1248.  
  1249. {
  1250.     MenuID        menuID = gMenuIDList->MenuIDFromResID(menuResID);
  1251.     
  1252.     MenuHandle theMenu = MAGetMenuHandle(menuID);        // First see if the menu is resident
  1253.  
  1254.     if (theMenu == NULL)                    // darn! Try the resource chain 
  1255.         theMenu = GetResMenu(menuResID);
  1256.  
  1257.     return theMenu;
  1258. } // MAGetMenu 
  1259.  
  1260. //----------------------------------------------------------------------------------------
  1261. // MAGetNewMBar: 
  1262. //----------------------------------------------------------------------------------------
  1263. #pragma segment MAInit
  1264.  
  1265. Handle MAGetNewMBar(ResNumber menuRsrcID)
  1266.  
  1267. {
  1268.     MCTableHandle theColorTab;
  1269.     Handle itsRsrcHandle;
  1270.     SignedByte savedState;
  1271.     Handle itsNewMBar;
  1272.  
  1273.     if (qNeedsColorQD || gConfiguration.hasColorQD)
  1274.         theColorTab = GetMCInfo();
  1275.  
  1276.     // make the 'MBAR' resource non-purgeable, so the Toolbox doesn't die 
  1277.     itsRsrcHandle = GetResource('MBAR', menuRsrcID);
  1278.     if (itsRsrcHandle)
  1279.     {
  1280.         savedState = HGetState(itsRsrcHandle);
  1281.         HNoPurge(itsRsrcHandle);
  1282.     }
  1283.  
  1284.     itsNewMBar = GetNewMBar(menuRsrcID);
  1285.  
  1286.     // restore the 'MBAR' resource 
  1287.     if (itsRsrcHandle)
  1288.         HSetState(itsRsrcHandle, savedState);
  1289.  
  1290.     if (theColorTab && (qNeedsColorQD || gConfiguration.hasColorQD))
  1291.     {
  1292.         HLock((Handle)theColorTab);
  1293.         SetMCEntries((short)(GetHandleSize((Handle)theColorTab) / sizeof(MCEntry)), (*theColorTab));
  1294.         HUnlock((Handle)theColorTab);
  1295.         DisposeMCInfo(theColorTab);
  1296.     }
  1297.  
  1298.     return itsNewMBar;
  1299. } // MAGetNewMBar 
  1300.  
  1301. //----------------------------------------------------------------------------------------
  1302. // MAInsertInMenuTable: 
  1303. //----------------------------------------------------------------------------------------
  1304. #pragma segment MAMenuRes
  1305.  
  1306. void MAInsertInMenuTable( MenuHandle theMenu, ResNumber menuResID )
  1307. {
  1308.     gMenuTable->Insert((Handle) theMenu);
  1309.     
  1310.     // Add the menu to the translation table
  1311.     gMenuIDList->AddToTable( menuResID, (*theMenu)->menuID );
  1312. } // MAInsertInMenuTable 
  1313.  
  1314. //----------------------------------------------------------------------------------------
  1315. // MAInsertMenu: 
  1316. //----------------------------------------------------------------------------------------
  1317. #pragma segment MAMenuRes
  1318.  
  1319. void MAInsertMenu(MenuHandle theMenu, ResNumber menuResID, MenuID beforeID)
  1320.  
  1321. {
  1322.     MenuCRsrcHandle theColorRsrc;
  1323.  
  1324.     InsertMenu(theMenu, beforeID);
  1325.         
  1326.     // Since only GetMenu automatically loads the appropriate color information,
  1327.     // and (sigh) since we can only call GetMenu once, and if you call DeleteMenu
  1328.     // all the good color stuff goes away (double sigh) we'll have to help out
  1329.     // the Menu Manager by doing its job for it
  1330.     
  1331.     if (qNeedsColorQD || gConfiguration.hasColorQD)
  1332.     {
  1333.         // n.b. This is using the menuID of the menu as a resource ID, which is incorrect
  1334.         theColorRsrc = (MenuCRsrcHandle)GetResource('mctb', menuResID);
  1335.         if (theColorRsrc)
  1336.         {
  1337.             HLock((Handle)theColorRsrc);
  1338.             SetMCEntries((*theColorRsrc)->numEntries, &((*theColorRsrc)->mcEntryRecs[0]));
  1339.             HUnlock((Handle)theColorRsrc);
  1340.             ReleaseResource((Handle)theColorRsrc);
  1341.         }
  1342.     }
  1343. } // MAInsertMenu 
  1344.  
  1345. //----------------------------------------------------------------------------------------
  1346. // NeedCalcMenuSize: 
  1347. //----------------------------------------------------------------------------------------
  1348. #pragma segment MAMenuRes
  1349.  
  1350. void NeedCalcMenuSize(MenuHandle aMenuHandle)
  1351. {
  1352.     if ((*aMenuHandle)->menuProc == pHNullMenuProc)
  1353.         (*aMenuHandle)->menuWidth = 0;
  1354. } // NeedCalcMenuSize 
  1355.  
  1356. //----------------------------------------------------------------------------------------
  1357. // NullMenuProc: a NULL menuProc that is used to inhibit re-calculating the menu's size
  1358. // after each call to EnableItem, CheckItem, etc.
  1359. //----------------------------------------------------------------------------------------
  1360. #pragma segment MAMenuRes
  1361.  
  1362. pascal void NullMenuProc(short,
  1363.                          MenuHandle aMenuHandle,
  1364.                          CRect& ,
  1365.                          CPoint,
  1366.                          short&)
  1367.  
  1368. {
  1369.     (*aMenuHandle)->menuWidth = 0;
  1370. } // NullMenuProc 
  1371.  
  1372. //----------------------------------------------------------------------------------------
  1373. // If hierarchical the range of IDs for applications is restricted.  See IM V-236.
  1374. const ResNumber kHierarchicalMin = 0;
  1375. const ResNumber kHierarchicalMax = 235;
  1376.  
  1377. typedef Boolean EnableArray[mLastMenu + 1];            // Saved enable flags 
  1378. typedef Handle SavePrArray[mLastMenu + 1];            // Saved menu procs 
  1379.  
  1380. struct SetupStruct
  1381. {
  1382.     EnableArray wasEnabled;
  1383.     SavePrArray savedProcs;
  1384. };
  1385.  
  1386.  
  1387. typedef SetupStruct* SetupStructPtr;
  1388.  
  1389. //----------------------------------------------------------------------------------------
  1390. // IsSetupMenu: 
  1391. //----------------------------------------------------------------------------------------
  1392. #pragma segment MAMenuRes
  1393.  
  1394. Boolean IsSetupMenu(MenuHandle aMenuHandle,
  1395.                     Boolean isHierarchical)
  1396.  
  1397. {
  1398.     if (!IsHandle((Handle) aMenuHandle))
  1399.     {
  1400. #if qDebug
  1401.         VerboseIsHandle((Handle) aMenuHandle);
  1402.         ProgramBreak("In IsSetupMenu: not handed a handle.");
  1403. #endif
  1404.         return false;
  1405.     }
  1406.     
  1407.     MenuID menuID = (*aMenuHandle)->menuID;
  1408.     
  1409.     if (menuID == mApple) return false;                        // _NEVER_ managed! 
  1410.  
  1411. #if qDebug
  1412.     if (menuID == mDebug) return true;
  1413. #endif
  1414.  
  1415.     if (isHierarchical)
  1416.     {
  1417.         if ((menuID < kHierarchicalMin) || (menuID > kHierarchicalMax))
  1418.             return false;    // must be in valid range for hierarchicals
  1419.     }
  1420.     return ((menuID >= mFirstMenu) && (menuID <= mLastMenu));    // Range of managed menus
  1421.     
  1422. } // IsSetupMenu 
  1423.  
  1424. //----------------------------------------------------------------------------------------
  1425. // StartMenuSetup: 
  1426. //----------------------------------------------------------------------------------------
  1427. void StartMenuSetup(MenuHandle aMenuHandle,
  1428.                     Boolean isHierarchical,
  1429.                     void* staticLink)
  1430. {
  1431.     if (IsSetupMenu(aMenuHandle, isHierarchical))
  1432.     {
  1433.         /* Remember the menu itself was enabled, and disable the menu
  1434.           and all of its items. */
  1435.         MenuID menuID = (*aMenuHandle)->menuID;
  1436.         ((SetupStructPtr)staticLink)->wasEnabled[menuID] = (Boolean)((*aMenuHandle)->enableFlags & 1);
  1437.         (*aMenuHandle)->enableFlags = 0;
  1438.  
  1439.         // Save the menu's menuproc and set it to the NullMenuProc, so that
  1440.         // CalcMenuSize is disabled (will do ÇalcMenuSize at end of setup).
  1441.         ((SetupStructPtr)staticLink)->savedProcs[menuID] = (*aMenuHandle)->menuProc;// See comment below 
  1442.         (*aMenuHandle)->menuProc = pHNullMenuProc;
  1443.         
  1444.         // Uncheck all items.
  1445.         short nItems = CountMItems(aMenuHandle);
  1446.         for (short item = 1; item <= nItems; ++item)// Make sure we don't check items with sub-menus 
  1447.         {
  1448.             short theCmd;
  1449.             GetItemCmd(aMenuHandle, item, &theCmd);
  1450.             if (theCmd != hMenuCmd)
  1451.                 CheckItem(aMenuHandle, item, false);// moves/purges memory 
  1452.         }
  1453.     }
  1454. } // StartMenuSetup 
  1455.  
  1456.  
  1457. //----------------------------------------------------------------------------------------
  1458. // EndMenuSetup: 
  1459. //----------------------------------------------------------------------------------------
  1460. void EndMenuSetup(MenuHandle aMenuHandle,
  1461.                   Boolean isHierarchical,
  1462.                   void* staticLink)
  1463.  
  1464. {
  1465.     long newFlags;
  1466.  
  1467.     if (IsSetupMenu(aMenuHandle, isHierarchical))
  1468.     {
  1469.         newFlags = (*aMenuHandle)->enableFlags;
  1470.         // If any items are enabled, enable the menu 
  1471.         if (newFlags != 0)
  1472.         {
  1473.             newFlags = (1 | newFlags);
  1474.             (*aMenuHandle)->enableFlags = newFlags;
  1475.         }
  1476.  
  1477.         // If the menu's enabled state changed, we have to draw the menu bar. 
  1478.         if (((newFlags & 1) == 1) != ((SetupStructPtr)staticLink)->wasEnabled[(*aMenuHandle)->menuID])
  1479.             InvalidateMenuBar();
  1480.  
  1481.         // Restore the menuproc. 
  1482.         (*aMenuHandle)->menuProc = ((SetupStructPtr)staticLink)->savedProcs[(*aMenuHandle)->menuID];
  1483.         
  1484.         // menuWidth set to 0 by routines that require CalcMenuSize, by
  1485.         // calling NeedCalcMenu.
  1486.         if (!(*aMenuHandle)->menuWidth)
  1487.             CalcMenuSize(aMenuHandle);
  1488.     }
  1489. } // EndMenuSetup 
  1490.  
  1491. //----------------------------------------------------------------------------------------
  1492. // PerformMenuSetup: 
  1493. //----------------------------------------------------------------------------------------
  1494. void PerformMenuSetup(MenuSetupType TheMenuSetterUpper, void* staticLink)
  1495.  
  1496. {
  1497.     SetupStruct itsSetupStruct;
  1498.  
  1499.     {// in a block to destroy the iterator
  1500.         CMenuIterator iter;
  1501.         for (MenuHandle item = iter.FirstMenu(); iter.More(); item = (MenuHandle)iter.NextMenu())
  1502.             StartMenuSetup(item, kHierarchical, &itsSetupStruct);
  1503.     }
  1504.  
  1505.     TheMenuSetterUpper(staticLink);
  1506.  
  1507.     {// in a block to destroy the iterator
  1508.         CMenuIterator iter;
  1509.         for (MenuHandle item = iter.FirstMenu(); iter.More(); item = (MenuHandle)iter.NextMenu())
  1510.             EndMenuSetup(item, kHierarchical, &itsSetupStruct);
  1511.     }
  1512.  
  1513.     if (MenuBarHasPendingUpdate())                // Never executed on system with InvalMenuBar
  1514.     {
  1515.         // if InvalMenuBar is available don't redraw the menubar directly
  1516.         if (!qNeedsSystem7 || !TrapExists(_InvalMenuBar))
  1517.             DrawMenuBar();
  1518.         ValidateMenuBar();
  1519.     }
  1520.  
  1521.     ValidateMenus();
  1522. } // PerformMenuSetup 
  1523.  
  1524. //----------------------------------------------------------------------------------------
  1525. // SetCommandIcon: 
  1526. //----------------------------------------------------------------------------------------
  1527. #pragma segment MAMenuRes
  1528.  
  1529. void SetCommandIcon(CommandNumber aCommand,
  1530.                     Byte menuIcon)
  1531.  
  1532. {
  1533.     MenuID menuID;
  1534.     short item;
  1535.     MenuHandle aMenuHandle;
  1536.  
  1537. #if qDebugMsg
  1538.     if (gTraceSetupMenus)
  1539.         fprintf(stderr, "..... SetCommandIcon(%c%d)\n", TraceMenuName(aCommand), menuIcon);
  1540. #endif
  1541.  
  1542.     aMenuHandle = CommandToComponents(aCommand, menuID, item);
  1543.     if (aMenuHandle)
  1544.         SetItemIcon(aMenuHandle, item, menuIcon);
  1545. } // SetCommandIcon 
  1546.  
  1547. //----------------------------------------------------------------------------------------
  1548. // SetCommandName: 
  1549. //----------------------------------------------------------------------------------------
  1550. #pragma segment MAMenuRes
  1551.  
  1552. void SetCommandName(CommandNumber aCommand,
  1553.                     const CStr255& menuText)
  1554.  
  1555. {
  1556.     MenuID menuID;
  1557.     short item;
  1558.     MenuHandle aMenuHandle;
  1559.  
  1560. #if qDebugMsg
  1561.     if (gTraceSetupMenus)
  1562.         fprintf(stderr, "..... SetCommandName(%c“%s”)\n", TraceMenuName(aCommand), (char *) menuText);
  1563. #endif
  1564.  
  1565. #if qDebug
  1566.     if (menuText.IsEmpty())
  1567.         ProgramBreak("SetCommandName: empty menuText - may corrupt the menu handle!");
  1568. #endif
  1569.  
  1570.     aMenuHandle = CommandToComponents(aCommand, menuID, item);
  1571.     if (aMenuHandle)
  1572.         SetMenuItemText(aMenuHandle, item, menuText);
  1573. } // SetCommandName 
  1574.  
  1575. //----------------------------------------------------------------------------------------
  1576. // SetIndividualCommandName: 
  1577. //----------------------------------------------------------------------------------------
  1578. #pragma segment MAMenuRes
  1579.  
  1580. void SetIndividualCommandName(CommandNumber aCommand,
  1581.                                 ResNumber rsrcID,
  1582.                               short strIndex)
  1583.  
  1584. {
  1585.     CStr255 s;
  1586.  
  1587.     GetIndString(s, rsrcID, strIndex);
  1588.     SetCommandName(aCommand, s);
  1589. } // SetIndividualCommandName 
  1590.  
  1591. //----------------------------------------------------------------------------------------
  1592. // SetMenuState: 
  1593. //----------------------------------------------------------------------------------------
  1594. #pragma segment MAMenuRes
  1595.  
  1596. void SetMenuState(CommandNumber aCommand,
  1597.                   ResNumber rsrcID,
  1598.                   short falseBuzzItem,
  1599.                   short trueBuzzItem,
  1600.                   Boolean stateVariable)
  1601.  
  1602. {
  1603.     short buzzItem;
  1604.  
  1605.     if (stateVariable)
  1606.         buzzItem = trueBuzzItem;
  1607.     else
  1608.         buzzItem = falseBuzzItem;
  1609.  
  1610.     SetIndividualCommandName(aCommand, rsrcID, buzzItem);
  1611. } // SetMenuState 
  1612.  
  1613. //----------------------------------------------------------------------------------------
  1614. // SetStyle: 
  1615. //----------------------------------------------------------------------------------------
  1616. #pragma segment MAMenuRes
  1617.  
  1618. void SetStyle(CommandNumber aCommand, /* Style */ short aStyle)
  1619.  
  1620. {
  1621.     MenuID menuID;
  1622.     short item;
  1623.     MenuHandle aMenuHandle;
  1624.  
  1625. #if qDebugMsg
  1626.     if (gTraceSetupMenus)
  1627.         fprintf(stderr, "..... SetStyle(%c%d)\n", TraceMenuName(aCommand), *((Ptr) & aStyle));
  1628. #endif
  1629.  
  1630.     aMenuHandle = CommandToComponents(aCommand, menuID, item);
  1631.     if (aMenuHandle)
  1632.         SetItemStyle(aMenuHandle, item, aStyle);
  1633. } // SetStyle 
  1634.  
  1635.  
  1636.  
  1637. //========================================================================================
  1638. // CLASS CMenuIterator
  1639. //========================================================================================
  1640. #undef Inherited
  1641. #define Inherited CHandleIterator
  1642.  
  1643. //----------------------------------------------------------------------------------------
  1644. // CMenuIterator::CMenuIterator: A simple iterator for menus.
  1645. //----------------------------------------------------------------------------------------
  1646. #pragma segment MAMenuRes
  1647.  
  1648. CMenuIterator::CMenuIterator() : CHandleIterator(gMenuTable)
  1649. {
  1650. } // CMenuIterator::CMenuIterator 
  1651.  
  1652. //----------------------------------------------------------------------------------------
  1653. // CMenuIterator::~CMenuIterator: 
  1654. //----------------------------------------------------------------------------------------
  1655. #pragma segment IteratorRes
  1656.  
  1657. CMenuIterator::~CMenuIterator()
  1658. {
  1659. } // CMenuIterator::~CMenuIterator 
  1660.  
  1661. //----------------------------------------------------------------------------------------
  1662. // CMenuIterator::CurrentMenu: 
  1663. //----------------------------------------------------------------------------------------
  1664. #pragma segment MAMenuRes
  1665.  
  1666. MenuHandle CMenuIterator::CurrentMenu()
  1667. {
  1668.     return (MenuHandle)this->CurrentHandle();
  1669. } // CMenuIterator::CurrentMenu 
  1670.  
  1671. //----------------------------------------------------------------------------------------
  1672. // CMenuIterator::FirstMenu: 
  1673. //----------------------------------------------------------------------------------------
  1674. #pragma segment MAMenuRes
  1675.  
  1676. MenuHandle CMenuIterator::FirstMenu()
  1677. {
  1678.     return (MenuHandle)this->FirstHandle();
  1679. } // CMenuIterator::FirstMenu 
  1680.  
  1681. //----------------------------------------------------------------------------------------
  1682. // CMenuIterator::NextMenu: 
  1683. //----------------------------------------------------------------------------------------
  1684. #pragma segment MAMenuRes
  1685.  
  1686. MenuHandle CMenuIterator::NextMenu()
  1687. {
  1688.     return (MenuHandle)this->NextHandle();
  1689. } // CMenuIterator::NextMenu 
  1690.  
  1691. //----------------------------------------------------------------------------------------
  1692. // CMenuIterator::Advance: 
  1693. //----------------------------------------------------------------------------------------
  1694. #pragma segment MAMenuRes
  1695.  
  1696. void CMenuIterator::Advance()                    // override
  1697. {
  1698.     CHandleIterator::Advance();
  1699.  
  1700.     // only point at menus that are in the menulist
  1701.     if (this->More() && !::GetMenuHandle((*(this->CurrentMenu()))->menuID))
  1702.         this->Advance();
  1703. } // CMenuIterator::Advance 
  1704.  
  1705.  
  1706. //========================================================================================
  1707. // CLASS TMenuBarManager
  1708. //========================================================================================
  1709. #undef Inherited
  1710. #define Inherited TObject
  1711.  
  1712. #pragma segment MAInit
  1713. DefineClass(TMenuBarManager, Inherited);
  1714.  
  1715. //----------------------------------------------------------------------------------------
  1716. // TMenuBarManager::TMenuBarManager: Empty constructor to satisfy the compiler.
  1717. //----------------------------------------------------------------------------------------
  1718. #pragma segment ConstructorRes
  1719.  
  1720. TMenuBarManager::TMenuBarManager()
  1721. {
  1722. } // TMenuBarManager::TMenuBarManager
  1723.  
  1724. //----------------------------------------------------------------------------------------
  1725. // TMenuBarManager::IMenuBarManager: 
  1726. //----------------------------------------------------------------------------------------
  1727. #pragma segment MAMenuRes
  1728. void TMenuBarManager::IMenuBarManager( ResNumber otherMenus )
  1729. {
  1730.     const CStr255 kParamText1 = "^0";
  1731.  
  1732.     this->IObject();
  1733.  
  1734.     fDisplayedMenus = kNoResource;
  1735.     fPreferredMenuBarID = kNoResource;
  1736.     fDisplayedHierMenus = kNoResource;
  1737.     fPreferredHierMenuBarID = kNoResource;
  1738.  
  1739.     // Add in the "other" menus, then clear them from the MenuBar
  1740.     AddMenuBar(otherMenus, false); 
  1741.     ClearMenuBar();
  1742.  
  1743.     // Initialize the Apple menu 
  1744.     MenuHandle aMenu = MAGetMenu(mApple);
  1745.     if (aMenu)
  1746.         AppendResMenu(aMenu, 'DRVR');
  1747.  
  1748.     // If the "About" item contains the paramtext keystring (^0) then substitute the
  1749.     // Application's name
  1750.     CStr255 s;
  1751.     CommandToName(cAboutApp, s);
  1752.     short i = s.Pos(kParamText1);
  1753.     if (i)
  1754.     {
  1755.         CStr255 apName;
  1756.  
  1757.         gApplication->GetApplicationName(apName);
  1758.         s.Delete(i, kParamText1.Length());
  1759.         s.Insert(apName, i);
  1760.         SetCommandName(cAboutApp, s);
  1761.     }
  1762. } // TMenuBarManager::IMenuBarManager 
  1763.  
  1764. //----------------------------------------------------------------------------------------
  1765. // TMenuBarManager::SetPreferredMenuBarID: 
  1766. //----------------------------------------------------------------------------------------
  1767. #pragma segment MAMenuRes
  1768. void TMenuBarManager::SetPreferredMenuBarID ( ResNumber theID )
  1769. {
  1770.     fPreferredMenuBarID = theID;
  1771. } // TMenuBarManager::SetPreferredMenuBarID 
  1772.  
  1773. //----------------------------------------------------------------------------------------
  1774. // TMenuBarManager::GetPreferredMenuBarID: 
  1775. //----------------------------------------------------------------------------------------
  1776. #pragma segment MAMenuRes
  1777. ResNumber TMenuBarManager::GetPreferredMenuBarID ()
  1778. {
  1779.     return fPreferredMenuBarID;
  1780. } // TMenuBarManager::GetPreferredMenuBarID 
  1781.  
  1782. //----------------------------------------------------------------------------------------
  1783. // TMenuBarManager::SetPreferredHierMenuBarID: 
  1784. //----------------------------------------------------------------------------------------
  1785. #pragma segment MAMenuRes
  1786. void TMenuBarManager::SetPreferredHierMenuBarID ( ResNumber theID )
  1787. {
  1788.     fPreferredHierMenuBarID = theID;
  1789. } // TMenuBarManager::SetPreferredHierMenuBarID 
  1790.  
  1791. //----------------------------------------------------------------------------------------
  1792. // TMenuBarManager::GetPreferredHierMenuBarID: 
  1793. //----------------------------------------------------------------------------------------
  1794. #pragma segment MAMenuRes
  1795. ResNumber TMenuBarManager::GetPreferredHierMenuBarID ()
  1796. {
  1797.     return fPreferredHierMenuBarID;
  1798. } // TMenuBarManager::GetPreferredHierMenuBarID 
  1799.  
  1800. //----------------------------------------------------------------------------------------
  1801. // TMenuBarManager::InstallPreferredMenus: 
  1802. //----------------------------------------------------------------------------------------
  1803. #pragma segment MAMenuRes
  1804. void TMenuBarManager::InstallPreferredMenus ()
  1805. {
  1806.     if(        ( (fDisplayedMenus != fPreferredMenuBarID)            && (fPreferredMenuBarID != kNoResource) )
  1807.         ||    ( (fDisplayedHierMenus != fPreferredHierMenuBarID)    && (fPreferredHierMenuBarID != kNoResource) )    )
  1808.     {
  1809.         ClearMenuBar();
  1810.  
  1811.         if (fPreferredMenuBarID != kNoResource)
  1812.         {
  1813.             AddMenuBar (fPreferredMenuBarID, false /* not hierarchical */);
  1814.             fDisplayedMenus = fPreferredMenuBarID;
  1815.         }
  1816.         else
  1817.             AddMenuBar (fDisplayedMenus, false /* not hierarchical */);
  1818.  
  1819.         if (fPreferredHierMenuBarID != kNoResource)
  1820.         {
  1821.             AddMenuBar (fPreferredHierMenuBarID, true /* hierarchical */);
  1822.             fDisplayedHierMenus = fPreferredHierMenuBarID;
  1823.         }
  1824.         else
  1825.             AddMenuBar (fDisplayedHierMenus, true /* hierarchical */);
  1826.         
  1827.         // We must reinsert the help menus whenever ClearMenuBar is called
  1828.         gApplication->InstallHelpMenuItems();
  1829.     }
  1830. } // TMenuBarManager::InstallPreferredMenus 
  1831.  
  1832. //----------------------------------------------------------------------------------------
  1833. // TMenuBarManager::Reset: 
  1834. //----------------------------------------------------------------------------------------
  1835. #pragma segment MAMenuRes
  1836. void TMenuBarManager::Reset ()
  1837. {
  1838.     fPreferredMenuBarID = kNoResource;
  1839.     fPreferredHierMenuBarID = kNoResource;
  1840. } // TMenuBarManager::Reset 
  1841.  
  1842. //----------------------------------------------------------------------------------------
  1843. // TMenuBarManager::AddHelpMenuItem: 
  1844. //----------------------------------------------------------------------------------------
  1845. #pragma segment MAMenuRes
  1846.  
  1847. void TMenuBarManager::AddHelpMenuItem( CStr255 helpText, CommandNumber helpCommand )
  1848. {
  1849.     MenuHandle        helpMenu = NULL;
  1850.     short            newHelpItemNo = 9999;
  1851.     const CStr255    kParamText1 = "^0";
  1852.     OSErr            err = noErr;
  1853.     
  1854.     // If the help item contains the paramtext keystring (^0) then substitute the
  1855.     // Application's name
  1856.     short i = helpText.Pos(kParamText1);
  1857.     if (i)
  1858.     {
  1859.         CStr255 apName;
  1860.  
  1861.         gApplication->GetApplicationName(apName);
  1862.         helpText.Delete(i, kParamText1.Length());
  1863.         helpText.Insert(apName, i);
  1864.     }
  1865.  
  1866.     // Put the help item at the end of the help menu if it's available
  1867.     if( gConfiguration.hasHelpMgr )
  1868.     {
  1869.         err = HMGetHelpMenuHandle( &helpMenu );
  1870.     }
  1871.     // If there's no help menu, then put the help item into the Apple menu
  1872.     else
  1873.     {
  1874.         helpMenu = ::GetMenuHandle( mApple );    // In System 6, the Apple menu serves as the help menu
  1875.         if( helpMenu != NULL )
  1876.         {
  1877.             CStr255        menuText;
  1878.             short        nAppleItems = CountMItems( helpMenu );
  1879.             
  1880.             // Put the help items right at the dividing line before the desk accessories
  1881.             newHelpItemNo = 1;
  1882.             while( newHelpItemNo <= nAppleItems )
  1883.             {
  1884.                 GetMenuItemText( helpMenu, newHelpItemNo, menuText );
  1885.                 if( menuText == "-" )
  1886.                     break;
  1887.                 
  1888.                 // If the help item is already in this menu, do nothing
  1889.                 if( menuText == helpText )
  1890.                     return;
  1891.                 
  1892.                 ++newHelpItemNo;
  1893.             }
  1894.         }
  1895.     }
  1896.     
  1897.     // If we have a reference to a menu, insert the help command
  1898.     if( (err == noErr) && (helpMenu != NULL) )
  1899.     {
  1900.         short        oldMenu;
  1901.         short        oldItem;
  1902.         
  1903.         // If the new help item is to be inserted at the end of
  1904.         // the list, make sure that its number is correct
  1905.         short nHelpItems = CountMItems( helpMenu );
  1906.         if( newHelpItemNo > nHelpItems )
  1907.             newHelpItemNo = nHelpItems + 1;
  1908.         
  1909.         // Insert the menu, then change its name.  This avoids problems
  1910.         // that might occur if the application name included metacharacters
  1911.         CStr255 helpStr = "Help";
  1912.         insertmenuitem( helpMenu, helpStr, newHelpItemNo - 1 );
  1913.         SetMenuItemText( helpMenu, newHelpItemNo, helpText );
  1914.         
  1915.         // Add the help command number to the command table, but only if it's not already there
  1916.         if( CommandToComponents(helpCommand,oldMenu,oldItem) == NULL )
  1917.             gCmdTable->AddToTable(helpCommand, (*helpMenu)->menuID, newHelpItemNo);
  1918.     }
  1919. } // TMenuBarManager::AddHelpMenuItem 
  1920.  
  1921. //----------------------------------------------------------------------------------------
  1922. // TMenuBarManager::AddMenuItem:
  1923. //----------------------------------------------------------------------------------------
  1924. #pragma segment MAMenuRes
  1925.  
  1926. void TMenuBarManager::AddMenuItem(const CStr255& theMenuItemText,
  1927.                                   MenuID menuNumber,
  1928.                                   short insertAfterItem,
  1929.                                   CommandNumber theMenuItemCommandNumber)
  1930. {
  1931.     short theMenuItem = insertAfterItem;
  1932.     MenuHandle theMenuHandle = GetMenuHandle(menuNumber);
  1933.     
  1934.     // If we have a reference to a menu, insert the new menu item
  1935.     if ((theMenuHandle != NULL) && (theMenuItemText.Length() > 0))
  1936.     {
  1937.         short    oldMenu;
  1938.         short    oldItem;
  1939.         short    curNumItems;
  1940.         
  1941.         // Figure out where to insert the new menu item
  1942.         curNumItems = CountMItems(theMenuHandle);
  1943.         if (theMenuItem > curNumItems)
  1944.             theMenuItem = curNumItems + 1;
  1945.         else
  1946.             // The user passed in where to insert it after so add one to take this into account
  1947.             theMenuItem++;
  1948.         
  1949.         // Insert the menu, then change its name.  This avoids problems
  1950.         // that might occur if the application name included metacharacters
  1951.         // One is subtracted here to take into account insert after item that InsMenuItem does
  1952.         ::InsertMenuItem(theMenuHandle, (ConstStr255Param)"\ptemp", theMenuItem - 1);
  1953.         ::SetMenuItemText(theMenuHandle, theMenuItem, theMenuItemText);
  1954.         
  1955.         // Add the help command number to the command table, but only if it's not already there
  1956.         if( CommandToComponents(theMenuItemCommandNumber, oldMenu, oldItem) == NULL )
  1957.             gCmdTable->AddNewCmdToTableAndUpdateTable(theMenuItemCommandNumber, (*theMenuHandle)->menuID, theMenuItem);
  1958.     
  1959.         // Make sure the menu is updated
  1960.         NeedCalcMenuSize(theMenuHandle);
  1961.     }
  1962. } // TMenuBarManager::AddMenuItem 
  1963.  
  1964. //----------------------------------------------------------------------------------------
  1965. // TMenuBarManager::DeleteMenuItem:
  1966. //----------------------------------------------------------------------------------------
  1967. #pragma segment MAMenuRes
  1968.  
  1969. void TMenuBarManager::DeleteMenuItem(CommandNumber theMenuItemCommandNumber)
  1970. {
  1971.     short    theMenuNumber;
  1972.     short    theItemNumber;
  1973.     
  1974.     gCmdTable->CommandToMenuItem(theMenuItemCommandNumber, theMenuNumber, theItemNumber);
  1975.     if (theMenuNumber)
  1976.     {
  1977.         MenuHandle theMenu = MAGetMenuHandle(theMenuNumber);
  1978.         
  1979.         // Delete the menu item from the menu
  1980.         if (theMenu != NULL)
  1981.         {
  1982.             ::DeleteMenuItem(theMenu, theItemNumber);
  1983.         
  1984.             // Make sure the menu is updated
  1985.             NeedCalcMenuSize(theMenu);
  1986.         }
  1987.         
  1988.         // Delete the command number from the table
  1989.         gCmdTable->DeleteCmdAndUpdateTable(theMenuItemCommandNumber);
  1990.     }
  1991. } // TMenuBarManager::DeleteMenuItem 
  1992.  
  1993.